package com.bym.mall.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bym.mall.entity.Cart;
import com.bym.mall.entity.Product;
import com.bym.mall.enums.ProductStatusEnum;
import com.bym.mall.enums.ResponseEnum;
import com.bym.mall.form.CartAddForm;
import com.bym.mall.form.CartUpdateForm;
import com.bym.mall.mapper.CartMapper;
import com.bym.mall.mapper.ProductMapper;
import com.bym.mall.service.ICartService;
import com.bym.mall.utils.UserUtil;
import com.bym.mall.vo.CartProductVo;
import com.bym.mall.vo.CartVo;
import com.bym.mall.vo.ResponseVo;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

    private final static String CART_REDIS_KEY_TEMPLATE = "CartService:cart:%d";

    @Resource
    private ProductMapper productMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private Gson gson = new Gson();

    @Override
    public ResponseVo<CartVo> add(CartAddForm cartAddForm) {
        //商品是否存在
        Product product = productMapper.selectById(cartAddForm.getProductId());
        if (ObjectUtil.isNull(product)) {
            return ResponseVo.error(ResponseEnum.PRODUCT_NOT_EXIST);
        }

        //商品是否正常在售
        if (!product.getStatus().equals(ProductStatusEnum.ON_SALE.getCode())) {
            return ResponseVo.error(ResponseEnum.PRODUCT_OFF_SALE_OR_DELETE);
        }

        //商品库存是否充足
        if (product.getStock() - cartAddForm.getQuantity() <= 0) {
            return ResponseVo.error(ResponseEnum.PROODUCT_STOCK_ERROR);
        }

        //将商品信息写入购物车
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());   //redisKey:cart_1
        String cartJson = opsForHash.get(redisKey, String.valueOf(product.getId()));
        Cart cart = null;
        if (StrUtil.isEmpty(cartJson)) {
            //没有该商品，向购物车新增该商品
            cart = new Cart();
            cart.setProductId(product.getId());
            cart.setQuantity(cartAddForm.getQuantity());
            cart.setSelected(cartAddForm.getSelected());
        } else {
            //购物车有该商品，该商品的数量+quantity
            cart = JSONUtil.toBean(cartJson, Cart.class);
            cart.setQuantity(cart.getQuantity() + cartAddForm.getQuantity());
        }
        opsForHash.put(redisKey, String.valueOf(product.getId()), JSONUtil.toJsonStr(cart));

        return newList();
    }

    @Override
    public ResponseVo<CartVo> newList() {
        //默认为空购物车
        CartVo cartVo = new CartVo();

        //先从redis中查询用户购物车
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String redisKey = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        Map<String, String> entries = opsForHash.entries(redisKey);

        //判断该购物车是否为空
        if (CollectionUtil.isNotEmpty(entries)) {
            //首先获取购物车中的商品id集合
            ArrayList<Integer> productIds = new ArrayList<>();
            for (Map.Entry<String, String> entry : entries.entrySet()) {
                Integer productId = Integer.valueOf(entry.getKey());
                productIds.add(productId);
            }

            //todo:从redis中获取products，而不是mysql中
            List<Product> products = productMapper.selectBatchIds(productIds);
            ArrayList<CartProductVo> cartProductVos = new ArrayList<>();
            boolean selectedAll = true;
            Integer totalQuantity = 0;
            BigDecimal totalPrice = new BigDecimal(0);

            for (Product product : products) {
                String cartJson = entries.get(String.valueOf(product.getId()));
                Cart cart = JSONUtil.toBean(cartJson, Cart.class);
                CartProductVo cartProductVo = new CartProductVo();
                cartProductVo.setProductId(product.getId());
                cartProductVo.setQuantity(cart.getQuantity());
                cartProductVo.setProductName(product.getName());
                cartProductVo.setProductSubtitle(product.getSubtitle());
                cartProductVo.setProductMainImage(product.getMainImage());
                cartProductVo.setProductPrice(product.getPrice());
                cartProductVo.setProductStatus(product.getStatus());
                cartProductVo.setProductStock(product.getStock());
                cartProductVo.setProductTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity())));
                cartProductVo.setProductSelected(cart.getSelected());
                cartProductVos.add(cartProductVo);

                //是否全选
                if (!cart.getSelected()) {
                    selectedAll = false;
                }

                //被勾选商品的总价
                if (cart.getSelected()) {
                    totalPrice = totalPrice.add(cartProductVo.getProductTotalPrice());
                }

                //购物车中商品的数量
                totalQuantity += cart.getQuantity();
            }

            cartVo.setCartProductVoList(cartProductVos);
            cartVo.setSelectedAll(selectedAll);
            cartVo.setCartTotalQuantity(totalQuantity);
            cartVo.setCartTotalPrice(totalPrice);

            //返回从redis中获得的购物车
            return ResponseVo.success(cartVo);
        }

        return ResponseVo.success(cartVo);
    }

    @Override
    public ResponseVo<CartVo> update(CartUpdateForm cartUpdateForm) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        String cartJson = opsForHash.get(key, String.valueOf(cartUpdateForm.getProductId()));

        //购物车中无此商品信息
        if (ObjectUtil.isNull(cartJson)) {
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }

        //更新购物车中的商品信息
        Cart cart = JSONUtil.toBean(cartJson, Cart.class);
        cart.setQuantity(cartUpdateForm.getQuantity());
        cart.setSelected(cartUpdateForm.getSelected());
        opsForHash.put(key, String.valueOf(cartUpdateForm.getProductId()), JSONUtil.toJsonStr(cart));

        return newList();
    }

    @Override
    public ResponseVo<CartVo> delete(Integer productId) {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        String cartJson = opsForHash.get(key, String.valueOf(productId));

        //购物车中无该商品
        if (ObjectUtil.isNull(cartJson)) {
            return ResponseVo.error(ResponseEnum.CART_PRODUCT_NOT_EXIST);
        }

        //删除购物车中的此商品
        opsForHash.delete(key, String.valueOf(productId));

        return newList();
    }

    @Override
    public ResponseVo<CartVo> selectAll() {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        Map<String, String> entries = opsForHash.entries(key);
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = JSONUtil.toBean(entry.getValue(), Cart.class);
            cart.setSelected(true);
            opsForHash.put(key, entry.getKey(), JSONUtil.toJsonStr(cart));
        }

        return newList();
    }

    @Override
    public ResponseVo<CartVo> unSelectAll() {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        Map<String, String> entries = opsForHash.entries(key);

        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = JSONUtil.toBean(entry.getValue(), Cart.class);
            cart.setSelected(false);
            opsForHash.put(key, entry.getKey(), JSONUtil.toJsonStr(cart));
        }

        return newList();
    }

    @Override
    public ResponseVo<Integer> sum() {
        ResponseVo<CartVo> responseVo = newList();
        CartVo cartVo = responseVo.getData();
        Integer cartTotalQuantity = cartVo.getCartTotalQuantity();
        return ResponseVo.success(cartTotalQuantity);
    }

    @Override
    public List<Cart> listForCart() {
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        Map<String, String> entries = opsForHash.entries(key);

        List<Cart> cartList = new ArrayList<>();
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            cartList.add(gson.fromJson(entry.getValue(), Cart.class));
        }

        return cartList;
    }

    @Override
    public ResponseVo persistCart() {
        //从redis中查询购物车
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        Map<String, String> entries = opsForHash.entries(key);

        //用户没有购物车
        if (CollectionUtil.isEmpty(entries)) {
            return ResponseVo.success();
        }

        //将购物车持久化至MySQL
        //首先删除旧购物车数据
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", UserUtil.getUser().getId());
        this.remove(queryWrapper);

        //然后新增新购物车数据
        ArrayList<Cart> carts = new ArrayList<>();
        for (Map.Entry<String, String> entry : entries.entrySet()) {
            Cart cart = JSONUtil.toBean(entry.getValue(), Cart.class);
            cart.setUserId(UserUtil.getUser().getId());
            carts.add(cart);
        }
        boolean b2 = this.saveBatch(carts);
        if (!b2) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        //最后删除redis中的购物车
        Boolean b3 = redisTemplate.delete(key);
        if (!b3) {
            return ResponseVo.error(ResponseEnum.ERROR);
        }

        return ResponseVo.success();
    }

    @Override
    public ResponseVo cacheCart() {
        //从数据库加载购物车
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", UserUtil.getUser().getId());
        List<Cart> carts = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(carts)) {
            return ResponseVo.success();
        }

        //将购物车缓存至redis
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, UserUtil.getUser().getId());
        for (Cart cart : carts) {
            opsForHash.put(key, String.valueOf(cart.getProductId()), JSONUtil.toJsonStr(cart));
        }

        return newList();
    }

    @Override
    public ResponseVo cacheCart(Integer uid) {
        //从数据库加载购物车
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", uid);
        List<Cart> carts = this.list(queryWrapper);
        if (CollectionUtil.isEmpty(carts)) {
            return ResponseVo.success();
        }

        //将购物车缓存至redis
        HashOperations<String, String, String> opsForHash = redisTemplate.opsForHash();
        String key = String.format(CART_REDIS_KEY_TEMPLATE, uid);
        for (Cart cart : carts) {
            opsForHash.put(key, String.valueOf(cart.getProductId()), JSONUtil.toJsonStr(cart));
        }

        return ResponseVo.success();
    }
}
